#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
#include "Socket.hpp"
#include "Log.hpp"
#include "Epoller.hpp"
#include <memory>
using namespace std;
using namespace Net_Work;
using namespace EpollerModule;
const int maxevent = 64;
const int default_backlog = 5;


class EpollServer {
public :
    EpollServer(int port)
        :_port(port)
        ,_isrunning(false)
        ,_listensocket(new TcpSocket())
        ,_epoller(new Epoller())
    {

    }

    void InitServer() {
        // 创建监听套接字
        _listensocket->BuildListenSocketMethod(_port, default_backlog);
        // 创建epoller
        _epoller->InitEpoller();
        // 将监听套接字添加到epoller中
        _epoller->AddEvent(_listensocket->GetSockFd(), EPOLLIN);
        _fds_set.insert(_listensocket->GetSockFd());
    }

    string EventToString(uint32_t events) {
        string info;
        if (events & EPOLLIN) {
            info += "EPOLLIN ";
        }
        if (events & EPOLLOUT) {
            info += "EPOLLOUT ";
        }
        if (events & EPOLLERR) {
            info += "EPOLLERR ";
        }
        return info;
    }

    void Recv(int sockfd) {
        char buffer[1024];
        int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0) {
            buffer[n] = '\0';
            pthread_mutex_lock(&mtx);
            cout << "client say# " << buffer << endl;
            pthread_mutex_unlock(&mtx);
            string message = "server say# ";
            message += buffer;
            n = send(sockfd, message.c_str(), message.size(), 0);
        } else {
            if (n == 0) {
                lg.LogMessage(Info, "对端关闭连接");
            } else {
                lg.LogMessage(Error, "读取出错,error errorno: %d, errorstring: %s", errno, strerror(errno));
            }
            // 从epoller删除事件
            _epoller->DelEvent(sockfd);
            _fds_set.erase(sockfd);
            close(sockfd);
        }

    }

    void HandlerEvent(int n) {
        for (int i = 0; i < n; i++) {
            int sockfd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;
            if (events & EPOLLIN) {
                lg.LogMessage(Info, "有一个就绪事件到来, 就绪事件是: %s", EventToString(events).c_str());
                if (sockfd == _listensocket->GetSockFd()) {
                    string clientip;
                    uint16_t clientport;
                    Socket* newsocket = _listensocket->AcceptConnection(&clientip, &clientport);
                    if (newsocket) {
                        lg.LogMessage(Info, "获取一个新链接, clientip: %s, clientport: %d", clientip.c_str(), clientport);
                        // 也将新链接添加到_epoller
                        _epoller->AddEvent(newsocket->GetSockFd(), EPOLLIN);
                        _fds_set.insert(newsocket->GetSockFd());
                    } else {
                        continue;
                    }
                } else {
                    // 处理读写
                    Recv(sockfd);
                }
            }

        }

    }

    void Loop() {
        _isrunning = true;
        while (_isrunning) {
            // 等待就绪时间
            int timeout = -1;
            int n = _epoller->Wait(_revs, maxevent, timeout);
            PrintDebug();
            if (n > 0) {
                pthread_mutex_unlock(&mtx);
                lg.LogMessage(Info, "有就绪事件到来, 当前有%d个就绪事件到来", n);
                // 处理事件
                HandlerEvent(n);
                
            } else if (n == 0) {
                lg.LogMessage(Debug, "timeout……");
            } else {
                lg.LogMessage(Error, "epoll wait error errorno: %d, errorstring: %s", errno, strerror(errno));
                break;
            }
        }
        _isrunning = false;
    }

    void PrintDebug() {
        pthread_mutex_lock(&mtx);
        cout << "当前的文件描述符有: ";
        for (auto x : _fds_set) {
            cout << x << " ";
        }
        cout << endl;
        pthread_mutex_unlock(&mtx);
    }

    ~EpollServer() {
    }
private :
    uint16_t _port;
    bool _isrunning;
    unique_ptr<Socket> _listensocket;
    unique_ptr<Epoller> _epoller;
    struct epoll_event _revs[maxevent];
    unordered_set<int> _fds_set;
};


